/*
 * Console.c
 *
 *  Created on: 2012-02-10
 *      Author: mxw
 */
#include <Console.h>
#include <cmd_def.h>
#include <commlib.h>

#include <music.h>
#include <svc.h>
#include <MainModu.h>
#include <LedDrv.h>
#include <music.h>
#include <UartDrv.h>
#include <KeyDrv.h>
#include <timer.h>
#include <SdMod.h>

extern int printf(const char* format, ...); //to be delete
extern void test_stmdb1();
extern void test_stmdb2();
extern void trigger_undef_instruction();
extern void trigger_data_abort();
extern void trigger_prefetch_abort();

#define UART_SEND_BUFF_LEN  10240
#define UART_RECV_BUFF_LEN  4096

CModule gConSend;
static char _uart_send_buf[UART_SEND_BUFF_LEN] = {0};

CModule gConRecv;
static char _uart_recv_buf[UART_RECV_BUFF_LEN] = {0};

void show_main_help();

static int on_uart_send_request(struct _cmodule_* thes, CMsg* msg) {
    int i = 0;
    while(i < msg->data_len) {
        uart_print_char(msg->data[i++]);
    }
    return 0;
}

extern void call_swi_test();
static void test_swi() {
    printf("before call swi\r\n");
    call_swi_test();
    printf("after call swi\r\n");
}

static void on_test_dis() {
    test_stmdb1();
    test_stmdb2();
}
static void on_ls_tsk() {
    CALL_SWI(SWI_LIST_ALL_TASK_INFO);
}

static void brief_tsk_req() {
    CALL_SWI(SWI_TASK_INFO_BRIEF);
}

static void test_led_all_on() {
    set_led(LED_ALL, LED_ON);
}
static void test_led_all_off() {
    set_led(LED_ALL, LED_OFF);
}

static int toneCnt = 0;
static int tid_bz = -1;
void on_time_test_bz(unsigned short tid) {
    ++toneCnt;
    if(toneCnt <= 5 * 7) {
        Buzzer_Freq_Set(freqTab[toneCnt]);
        return;
    }
    Buzzer_Stop();
    toneCnt = 0;
    stop_timer(tid_bz);
    delete_timer(tid_bz);
    tid_bz = -1;
}
static void test_buz() {
    tid_bz = get_new_timer(on_time_test_bz);
    start_timer(tid_bz, 30);
}

static void test_undef_instruction() {
    trigger_undef_instruction();
}
static void test_data_abort() {
    trigger_data_abort();
}

static void test_prefetch_abort() {
    trigger_prefetch_abort();
}

static void test_tmp() {
    int i = 0;
    
    char _rcv_msg_buf[16];
    CMsg* msg = (CMsg*)&_rcv_msg_buf[0];

    msg->msg_id = MSG_ID_TEST_SD_REQ;
    msg->data_len = 0;
    gSdMod.sendMsg(&gSdMod, msg);
	return;
	
    printf("key4 gkeyDownCnt:%d\r\n", gkeyDownInfo[3].gkeyDownCnt);
    for(; i < gkeyDownInfo[3].cnt; ++i) {
        printf("  tick::%d\r\n", gkeyDownInfo[3].tick[i]);
    }
    
    // printf("key1 gkeyDownCnt:%d\r\n", gkeyDownCnt[0]);
    // printf("key2 gkeyDownCnt:%d\r\n", gkeyDownCnt[1]);
    // printf("key3 gkeyDownCnt:%d\r\n", gkeyDownCnt[2]);
    // printf("key4 gkeyDownCnt:%d\r\n", gkeyDownCnt[3]);
}

static struct {
    char* cmd;
    void (*fn)();
    char* comment;
} cmdArr[] = {
    {"help", show_main_help, "show_main_help"}, 
    {"lstk", on_ls_tsk, "list all task info"}, 
    {"btsk", brief_tsk_req, "list task info brief"}, 
    {"mus", new_muisc_go, " play music"}, 
    {"s", request_to_stop, "   stop music-playing"}, 
    {"tds", on_test_dis, " test ldm/stm instruction"}, 
    {"tsi", test_swi, " test swi call"}, 
    {"tln", test_led_all_on, " test all led on"}, 
    {"tlf", test_led_all_off, " test all led off"}, 
    {"tbz", test_buz, " test buzzer on"}, 
    {"tui", test_undef_instruction, " [!FATAL!]test undef instruction(need restart to recovery)"},
    {"tda", test_data_abort, " [!FATAL!]test data abort(need restart to recovery)"},
    {"tpa", test_prefetch_abort, " [!FATAL!]test prefetch abort(need restart to recovery) ->DO NOT WORK now."},
    
    {"t", test_tmp, "   trigger for some tmp debug"}, 

};

void show_main_help() {
    int i = 0;
    for(; i < sizeof(cmdArr) / sizeof(cmdArr[0]); ++i) {
        printf("%s    %s\r\n", cmdArr[i].cmd, cmdArr[i].comment);
    }
    return;

    //printf("    show this help.\r\n");
    printf("mus [-l] [-p list_num] [-n play_word_count] [-s skip_word_cnt]\r\n");
    printf("  `s` to stop.\r\n");
    //printf("    -l list the music name.\r\n");
    //printf("    -p num_in_list   to play the music. -s -n option is effective.\r\n");
    printf("test [dis] [led] [buz] [timer] [abort_prefetch] [abort_data] [undef_instr]\r\n");
    printf("test [reserve]\r\n");
}


static int parse_cmd(char* cmd) {
    int i = 0;
    for(; i < sizeof(cmdArr) / sizeof(cmdArr[0]); ++i) {
        if(0 == strcmp(cmdArr[i].cmd, cmd)) {
            (*cmdArr[i].fn)();
            return 0;
        }
    }
    printf("unkonw command.\r\n");
    return 0;
}

#define CPS_IDLE        0
#define CPS_LISTENING   1
static int on_uart_recv_arrive(struct _cmodule_* thes, CMsg* msg) {
    static char _lbuf[32] = {0};
    static unsigned char _lbuf_idx = 0;
    static char cmd_parser_st = CPS_IDLE;
    if(MSG_ID_UART_RECV_CHAR == msg->msg_id) {
        //echo
        if ('\n' == msg->data[0] || '\r' == msg->data[0]) {
            printf("\r\n");
        } if('\b' == msg->data[0]) {
            printf("\b \b");
        } else {
            printf("%c", msg->data[0]);
        }

        //parsing
        switch(cmd_parser_st) {
        case CPS_IDLE:
            if('\n' == msg->data[0] || '\r' == msg->data[0]) {
                return 0;
            }
            _lbuf[_lbuf_idx++] = msg->data[0];
            cmd_parser_st = CPS_LISTENING;
            break;
        case CPS_LISTENING:
            if('\b' == msg->data[0]) {
                if(_lbuf_idx > 0) {
                    _lbuf[_lbuf_idx - 1] = '\0';
                    _lbuf_idx--;
                }
                return 0;
            }
            if('\n' == msg->data[0] || '\r' == msg->data[0]) {
                parse_cmd(_lbuf);
                _lbuf_idx = 0;
                memset(_lbuf, 0, sizeof(_lbuf));
                cmd_parser_st = CPS_IDLE;
                return 0;
            }

            _lbuf[_lbuf_idx++] = msg->data[0];
            if(_lbuf_idx >= sizeof(_lbuf)) {
                printf("\r\n[E]cmd too lang.\r\n");
                _lbuf_idx = 0;
                memset(_lbuf, 0, sizeof(_lbuf));
                cmd_parser_st = CPS_IDLE;
                return -1;
            }
            break;
        }
        //printf("yyyy recved char:%c(0x%X)\r\n", msg->data[0], (int)msg->data[0]);
    }    
    return 0;
}

void uart_on_recv_intr(unsigned char c) {
    char _rcv_msg_buf[16];
    CMsg* msg = (CMsg*)&_rcv_msg_buf[0];

    msg->msg_id = MSG_ID_UART_RECV_CHAR;
    msg->data_len = 1;
    msg->data[0] = (char)c;
    gConRecv.sendMsg(&gConRecv, msg);
}

int init_console_module() {
    construct_module(&gConSend, "uart send module", on_uart_send_request);
    gConSend.q.set_queue_buf(&gConSend.q, _uart_send_buf, UART_SEND_BUFF_LEN);
    gConSend.run(&gConSend);
    
    construct_module(&gConRecv, "uart recv module", on_uart_recv_arrive);
    gConRecv.q.set_queue_buf(&gConRecv.q, _uart_recv_buf, UART_RECV_BUFF_LEN);
    gConRecv.run(&gConRecv);
    return 0;
}

